import _ from 'underscore';
import Bb from 'backbone';
import {
    findCurrentSelected
} from '../../tools.js';


const BaseModel = Bb.Model.extend({
    /*
     * A Base model that add some extras functionnalities to the Base backbone model
     * 
     * allow to rollback current model model.rollback()
     * triggers some additionnal events :
     * 
     * ('destroyed') when a model has been effectively deleted
     * ('saved', attributes) when the attributes value has been saved server side
     * ('saved:attribute', value) for each attribute
     */
    // Props are used to describe the model and limit the attributes that
    // are set on it and send to the server.
    props: null,
    // itemBaseUrl can be defined to override the url used to fetch/save/delete an existing item
    // EX : /api/v1/files/
    itemBaseUrl: null,
    constructor: function () {
        arguments[0] = this.cleanProps(arguments[0]);
        Bb.Model.apply(this, arguments);
        this.save_xhr_request = null;
    },
    toJSON: function (options) {
        var attributes = _.clone(this.attributes);
        attributes = this.cleanProps(attributes);
        return attributes;
    },
    set: function (key, val, options) {
        // Hack Model.set pour filtrer selon les props (si props est spécifié)
        if (this.props) {
            if (typeof key === 'object') {
                key = this.cleanProps(key);
            } else {
                if (!this.props.includes(key)) {
                    key = null;
                }
            }
        }
        return Bb.Model.prototype.set.call(this, key, val, options);
    },
    _runSave(key, val, options) {
        let xhr_request = Bb.Model.prototype.save.call(this, key, val, options);
        if (xhr_request) {
            xhr_request.done(() => {
                if (_.isObject(key)) {
                    Object.keys(key).map((i) => {
                        console.log("Triggering saved : %s, value %s", i, key[i]);
                        this.trigger('saved:' + i, key[i]);
                    });
                    console.log("Triggering saved");
                    this.trigger('saved', key);
                } else {
                    console.log("Triggering saved : %s, value %s", key, val);
                    this.trigger('saved:' + key, val);
                    console.log("Triggering saved");
                    this.trigger('saved')
                }
            })
        }
        return xhr_request;
    },
    save: function (key, val, options) {
        if (this.itemBaseUrl !== null) {
            var url = this.itemBaseUrl + this.get('id');
            options = _.defaults((options || {}), {
                url: url
            });
        }
        if (this.save_xhr_request && this.save_xhr_request.state() == 'pending') {
            console.log("A request is pending for this model, we wait it ends")
            this.save_xhr_request = this.save_xhr_request.then(
                () => this._runSave(key, val, options)
            )
        } else {
            this.save_xhr_request = this._runSave(key, val, options);
        }
        return this.save_xhr_request;
    },
    destroy: function (options) {
        if (this.itemBaseUrl !== null) {
            var url = this.itemBaseUrl + this.get('id');
            options = _.defaults((options || {}), {
                url: url
            });
        }
        var collection = this.collection;
        let xhr_request = Bb.Model.prototype.destroy.call(this, options);
        if (xhr_request) {
            xhr_request.done(() => {
                console.log("Triggering destroyed");
                collection.trigger('destroyed')
            })
        }
        return xhr_request;
    },
    fetch: function (options) {
        if (this.itemBaseUrl !== null) {
            var url = this.itemBaseUrl + this.get('id');
            options = _.defaults((options || {}), {
                url: url
            });
        }
        return Bb.Model.prototype.fetch.call(this, options);
    },
    cleanProps(attributes) {
        if (!_.isNull(this.props)) {
            attributes = _.pick(attributes, this.props);
            attributes = _.omit(attributes, function (value) {
                return _.isNull(value) || _.isUndefined(value);
            });
        }
        return attributes;
    },
    rollback: function (remote) {
        if (this.get('id')) {
            if (remote) {
                this.fetch();
            } else {
                var changed = this.changedAttributes();

                if (!changed)
                    return;

                var keys = _.keys(changed);
                var prev = _.pick(this.previousAttributes(), keys);

                this.set(prev);
            }
        }
    },
    findLabelFromId(model_attr, label_key, options) {
        /*
         * Return the label of an option identified by it's id key
         * :param str model_attr: The foreign key key we use to search
         * :param str label_key: The "label" key of the related object
         * :param list options: List of potential related elements
         */
        let value = this.get(model_attr);
        let result = '-';
        if (value) {
            let option = findCurrentSelected(options, parseInt(value), "id");
            if (option) {
                result = option[label_key];
            }
        }
        return result
    },
});
export default BaseModel;